#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Web Page Generator Script
网页生成脚本

功能：
1. 读取分析结果数据
2. 生成专业的分析报告网页
3. 包含Mermaid图表和交互功能
4. 提供完整的用户体验

作者：Falcomm自研团队
版本：1.0
日期：2025-08-15
"""

import sys
import json
import argparse
from pathlib import Path
from datetime import datetime
from collections import defaultdict

class WebGenerator:
    def __init__(self):
        self.template_data = {}
        
    def generate_web_page(self, docs_dir, styles_dir, project_root):
        """生成分析报告网页"""
        docs_dir = Path(docs_dir)
        styles_dir = Path(styles_dir)
        project_root = Path(project_root)
        
        print(f"Starting analysis webpage generation...")
        
        try:
            # 查找分析结果文件
            analysis_files = list(docs_dir.glob("*_analysis.json"))
            if not analysis_files:
                print("No analysis result files found")
                return False
            
            # 读取分析结果
            analysis_data = self._load_analysis_data(analysis_files[0])
            
            # 生成HTML内容
            html_content = self._generate_html_content(analysis_data, styles_dir, docs_dir)
            
            # 保存HTML文件
            output_file = project_root / "sidebar_analysis.html"
            with open(output_file, 'w', encoding='utf-8') as f:
                f.write(html_content)
            
            print(f"Analysis webpage generated successfully: {output_file}")
            return True
            
        except Exception as e:
            print(f"Error generating webpage: {e}")
            import traceback
            traceback.print_exc()
            return False
    
    def _load_analysis_data(self, analysis_file):
        """加载分析结果数据"""
        print(f"Loading analysis results: {analysis_file.name}")
        
        with open(analysis_file, 'r', encoding='utf-8') as f:
            data = json.load(f)
        
        return data 

    def _generate_html_content(self, analysis_data, styles_dir, docs_dir):
        """生成HTML内容"""
        # 获取基础数据
        metadata = analysis_data.get("metadata", {})
        summary = analysis_data.get("summary", {})
        anomalies = analysis_data.get("anomalies", [])
        flows = analysis_data.get("flows", {})
        statistics = analysis_data.get("statistics", {})
        recommendations = analysis_data.get("recommendations", [])
        # 加载投诉上下文（若存在）
        complaint = self._load_complaint_context(docs_dir)
        
        # 计算准确的统计数据
        total_packets = summary.get('total_packets', 0)
        
        # 统计DNS查询数量 - DNS流数量的一半（每个查询包含请求和响应两个流）
        dns_flows = [f for f in flows.values() if f.get('protocol') == 'DNS']
        dns_queries = len(dns_flows) // 2  # 每个DNS查询包含请求和响应两个流
        
        # 统计TCP流数量
        tcp_flows = [f for f in flows.values() if f.get('protocol') == 'TCP']
        tcp_flow_count = len(tcp_flows)
        
        # 统计异常事件数量 - 按照实际数据计算
        # 计算不同类型的异常
        tcp_connection_anomalies = [a for a in anomalies if a.get('type') == 'TCP_CONNECTION_INCOMPLETE']
        tcp_retransmission_anomalies = [a for a in anomalies if a.get('type') == 'TCP_RETRANSMISSION']
        icmp_anomalies = [a for a in anomalies if 'ICMP' in a.get('type', '')]
        
        # 按照实际数据计算异常事件总数
        abnormal_events = len(tcp_connection_anomalies) + len(tcp_retransmission_anomalies) + len(icmp_anomalies)
        
        # 生成HTML
        html = f"""<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户面信令分析报告</title>
    <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
    <style>
{self._get_css_styles()}
    </style>
</head>
<body>
    <div class="main-container">
        <!-- 主内容区域 -->
        <div class="main-content" id="mainContent">
            <!-- 头部信息 -->
            <div class="header">
                <h1>用户面信令分析报告</h1>
                <div class="subtitle">Falcomm自研团队完成</div>
                <div class="stats-grid">
                    <div class="stat-card">
                        <div class="stat-number">{total_packets}</div>
                        <div class="stat-label">总数据包</div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-number">{dns_queries}</div>
                        <div class="stat-label">DNS查询</div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-number">{tcp_flow_count}</div>
                        <div class="stat-label">TCP流</div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-number">{abnormal_events}</div>
                        <div class="stat-label">异常事件</div>
                    </div>
                </div>
            </div>

            <!-- 具体信令流程分析 -->
            <div class="analysis-section">
                <h2>具体信令流程分析</h2>
                {self._generate_signaling_flow_content(flows, anomalies)}
            </div>

            <!-- 信令流程分析图 -->
            <div class="analysis-section">
                <h2>信令流程分析图</h2>
                {self._generate_signaling_flow_diagram(flows, anomalies, total_packets)}
            </div>

            <!-- 网络流分析 -->
            <div class="analysis-section">
                <h2>网络流分析</h2>
                {self._generate_flows_content(flows)}
            </div>

            <!-- 异常检测结果 -->
            <div class="analysis-section">
                <h2>异常检测结果</h2>
                {self._generate_anomalies_content(anomalies)}
            </div>

            <!-- 性能统计 -->
            <div class="analysis-section">
                <h2>性能统计</h2>
                {self._generate_statistics_content(statistics)}
            </div>

            <!-- 页脚 -->
            <div class="footer">
                <p>用户面信令分析报告 | 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
                <p>Falcomm自研团队 | 总包数: {total_packets} | 异常事件: {abnormal_events}</p>
            </div>
        </div>

        <!-- 右侧Sidebar -->
        <div class="sidebar collapsed" id="sidebar">
            <div class="sidebar-header">
                <h3>详细分析报告</h3>
                <p>点击右侧按钮展开/收起</p>
            </div>
            
            <div class="sidebar-content">
                <!-- 分析结论 -->
                <div class="sidebar-section">
                    <h4 onclick="toggleSection(this)">
                        分析结论
                        <button class="section-toggle" onclick="event.stopPropagation(); toggleSection(this.parentElement)">▶</button>
                    </h4>
                    <div class="section-content">
                        {self._generate_summary_content(summary, flows, anomalies)}
                    </div>
                </div>

                <!-- 关键异常点 -->
                <div class="sidebar-section">
                    <h4 onclick="toggleSection(this)">
                        关键异常点
                        <button class="section-toggle" onclick="event.stopPropagation(); toggleSection(this.parentElement)">▶</button>
                    </h4>
                    <div class="section-content">
                        {self._generate_key_anomalies_content(anomalies)}
                    </div>
                </div>

                <!-- 分析过程 -->
                <div class="sidebar-section">
                    <h4 onclick="toggleSection(this)">
                        分析过程
                        <button class="section-toggle" onclick="event.stopPropagation(); toggleSection(this.parentElement)">▶</button>
                    </h4>
                    <div class="section-content">
                        <div class="sub-section">
                            <div class="sub-item" onclick="toggleSubSection(this)">
                                异常流程
                                <span class="sub-toggle">▶</span>
                            </div>
                            <div class="sub-content">
                                {self._generate_abnormal_process_content(anomalies)}
                            </div>
                        </div>
                        <div class="sub-section">
                            <div class="sub-item" onclick="toggleSubSection(this)">
                                异常消息
                                <span class="sub-toggle">▶</span>
                            </div>
                            <div class="sub-content">
                                {self._generate_abnormal_message_content(anomalies)}
                            </div>
                        </div>
                        <div class="sub-section">
                            <div class="sub-item" onclick="toggleSubSection(this)">
                                异常信元
                                <span class="sub-toggle">▶</span>
                            </div>
                            <div class="sub-content">
                                {self._generate_abnormal_element_content(anomalies)}
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 相关知识解释 -->
                <div class="sidebar-section">
                    <h4 onclick="toggleSection(this)">
                        相关知识解释
                        <button class="section-toggle" onclick="event.stopPropagation(); toggleSection(this.parentElement)">▶</button>
                    </h4>
                    <div class="section-content">
                        <div class="sub-section">
                            <div class="sub-item" onclick="toggleSubSection(this)">
                                异常流程解释
                                <span class="sub-toggle">▶</span>
                            </div>
                            <div class="sub-content">
                                {self._generate_process_explanation_content()}
                            </div>
                        </div>
                        <div class="sub-section">
                            <div class="sub-item" onclick="toggleSubSection(this)">
                                异常消息解释
                                <span class="sub-toggle">▶</span>
                            </div>
                            <div class="sub-content">
                                {self._generate_message_explanation_content()}
                            </div>
                        </div>
                        <div class="sub-section">
                            <div class="sub-item" onclick="toggleSubSection(this)">
                                异常原因码解释
                                <span class="sub-toggle">▶</span>
                            </div>
                            <div class="sub-content">
                                {self._generate_reason_code_explanation_content()}
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 信元核查结果 -->
                <div class="sidebar-section">
                    <h4 onclick="toggleSection(this)">
                        信元核查结果
                        <button class="section-toggle" onclick="event.stopPropagation(); toggleSection(this.parentElement)">▶</button>
                    </h4>
                    <div class="section-content">
                        {self._generate_field_check_content(flows)}
                    </div>
                </div>

                <!-- 处理建议 -->
                <div class="sidebar-section">
                    <h4 onclick="toggleSection(this)">
                        处理建议
                        <button class="section-toggle" onclick="event.stopPropagation(); toggleSection(this.parentElement)">▶</button>
                    </h4>
                    <div class="section-content">
                        {self._generate_concise_recommendation_paragraph(recommendations, anomalies, flows, statistics, complaint)}
                    </div>
                </div>

                <!-- 问题原因及处理措施 -->
                <div class="sidebar-section">
                    <h4 onclick="toggleSection(this)">
                        问题原因及处理措施
                        <button class="section-toggle" onclick="event.stopPropagation(); toggleSection(this.parentElement)">▶</button>
                    </h4>
                    <div class="section-content">
                        <div class="sub-section">
                            <div class="sub-item" onclick="toggleSubSection(this)">
                                TCP建链失败原因
                                <span class="sub-toggle">▶</span>
                            </div>
                            <div class="sub-content">
                                {self._generate_tcp_connection_failure_reasons(anomalies)}
                            </div>
                        </div>
                        <div class="sub-section">
                            <div class="sub-item" onclick="toggleSubSection(this)">
                                TCP传输延迟原因
                                <span class="sub-toggle">▶</span>
                            </div>
                            <div class="sub-content">
                                {self._generate_tcp_transmission_delay_reasons(anomalies)}
                            </div>
                        </div>
                        <div class="sub-section">
                            <div class="sub-item" onclick="toggleSubSection(this)">
                                ICMP被禁止原因
                                <span class="sub-toggle">▶</span>
                            </div>
                            <div class="sub-content">
                                {self._generate_icmp_forbidden_reasons(anomalies)}
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 操作按钮 -->
                <div class="sidebar-section">
                    <h4>操作</h4>
                    <div style="text-align: center; padding: 15px;">
                        <button class="export-btn" onclick="printReport()">打印</button>
                        <button class="export-btn" onclick="saveAsHTML()">保存</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- Sidebar切换按钮 -->
        <button class="sidebar-toggle" id="sidebarToggle" onclick="toggleSidebar()">
            展开报告
        </button>
    </div>

    <script>
{self._get_javascript_code()}
    </script>
</body>
</html>"""
        
        return html

    def _generate_signaling_flow_content(self, flows, anomalies):
        """生成具体信令流程分析内容"""
        content = '<div class="signaling-flow-container">'
        
        # 生成Mermaid流程图
        mermaid_diagram = self._generate_mermaid_diagram(flows, anomalies)
        content += f'''
        <div class="mermaid-diagram">
            <h3>网络信令流程图</h3>
            <div class="mermaid">
                {mermaid_diagram}
            </div>
        </div>
        '''
        
        # 流程阶段分析
        content += '''
        <div class="flow-phases">
            <h3>流程阶段分析</h3>
            <div class="phase-analysis">
                <div class="phase-item">
                    <h4>DNS阶段</h4>
                    <p>域名解析过程，包括DNS查询和响应</p>
                </div>
                <div class="phase-item">
                    <h4>建链阶段</h4>
                    <p>TCP连接建立过程，包括SYN、SYN-ACK、ACK</p>
                </div>
                <div class="phase-item">
                    <h4>传输阶段</h4>
                    <p>数据传输过程，包括数据包交换</p>
                </div>
                <div class="phase-item">
                    <h4>拆链阶段</h4>
                    <p>连接断开过程，包括FIN、ACK</p>
                </div>
            </div>
        </div>
        '''
        
        content += '</div>'
        return content

    def _generate_signaling_flow_diagram(self, flows, anomalies, total_packets):
        """生成信令流程分析图"""
        # 统计各阶段数据
        dns_flows = [f for f in flows.values() if f.get('protocol') == 'DNS']
        tcp_flows = [f for f in flows.values() if f.get('protocol') == 'TCP']
        icmp_flows = [f for f in flows.values() if f.get('protocol') == 'ICMP']
        
        # 计算DNS查询数量
        dns_queries = len(dns_flows) // 2  # 每个DNS查询包含请求和响应两个流
        
        # 统计异常
        tcp_connection_anomalies = [a for a in anomalies if a.get('type') == 'TCP_CONNECTION_INCOMPLETE']
        tcp_transmission_anomalies = [a for a in anomalies if a.get('type') == 'TCP_RETRANSMISSION']
        icmp_anomalies = [a for a in anomalies if 'ICMP' in a.get('type', '')]
        
        # 计算正常数量
        normal_tcp_connections = len(tcp_flows) - len(tcp_connection_anomalies)
        normal_tcp_transmissions = len(tcp_flows) - len(tcp_transmission_anomalies)
        
        content = f'''
        <div class="signaling-flow-diagram">
            <div class="flow-chart">
                <div class="flow-item">
                    <div class="flow-header">开始: {total_packets}个数据包</div>
                    <div class="flow-arrow">↓</div>
                </div>
                
                <div class="flow-item">
                    <div class="flow-header">DNS查询阶段 ({dns_queries}个查询) ✅ 正常</div>
                    <div class="flow-arrow">↓</div>
                    <div class="flow-details">
                        <div class="flow-branch">┣— 正常响应 ({dns_queries}个) → 建链阶段</div>
                        <div class="flow-branch">┗— 无异常</div>
                    </div>
                    <div class="flow-arrow">↓</div>
                </div>
                
                <div class="flow-item">
                    <div class="flow-header">建链阶段 ({len(tcp_flows)}个TCP流)</div>
                    <div class="flow-arrow">↓</div>
                    <div class="flow-details">
                        <div class="flow-branch">┣— 正常连接 ({normal_tcp_connections}个) → 传输阶段</div>
                        <div class="flow-branch anomaly">┗— 连接失败 ({len(tcp_connection_anomalies)}个) → TCP建链异常 ▲</div>
                    </div>
                    <div class="flow-arrow">↓</div>
                </div>
                
                <div class="flow-item">
                    <div class="flow-header">传输阶段</div>
                    <div class="flow-arrow">↓</div>
                    <div class="flow-details">
                        <div class="flow-branch">┣— 正常传输 ({normal_tcp_transmissions}个)</div>
                        <div class="flow-branch anomaly">┗— 传输异常 ({len(tcp_transmission_anomalies)}个) → TCP传输异常 ▲</div>
                    </div>
                    <div class="flow-arrow">↓</div>
                </div>
                
                <div class="flow-item">
                    <div class="flow-header">ICMP传输</div>
                    <div class="flow-arrow">↓</div>
                    <div class="flow-details">
                        <div class="flow-branch">┣— 正常传输</div>
                        <div class="flow-branch anomaly">┗— 传输异常 ({len(icmp_anomalies)}个) → ICMP传输异常 ▲</div>
                    </div>
                    <div class="flow-arrow">↓</div>
                </div>
                
                <div class="flow-item">
                    <div class="flow-header">拆链阶段</div>
                    <div class="flow-arrow">↓</div>
                    <div class="flow-details">
                        <div class="flow-branch">正常结束</div>
                    </div>
                </div>
            </div>
            
            <div class="anomaly-summary">
                <h4>异常流程汇总</h4>
                <div class="anomaly-item">— TCP建链异常: {len(tcp_connection_anomalies)}个 ({len(tcp_connection_anomalies)/len(tcp_flows)*100:.0f}%)</div>
                <div class="anomaly-item">— TCP传输异常: {len(tcp_transmission_anomalies)}个 ({len(tcp_transmission_anomalies)/len(tcp_flows)*100:.0f}%)</div>
                <div class="anomaly-item">— ICMP传输异常: {len(icmp_anomalies)}个 ({len(icmp_anomalies)/len(tcp_flows)*100:.0f}%)</div>
            </div>
        </div>
        '''
        
        return content

    def _generate_mermaid_diagram(self, flows, anomalies):
        """基于分析数据动态生成Mermaid流程图"""
        # 收集所有参与者的IP地址，去重
        participants = set()
        for flow_key, flow_info in flows.items():
            if flow_info.get('src_ip'):
                participants.add(flow_info['src_ip'])
            if flow_info.get('dst_ip'):
                participants.add(flow_info['dst_ip'])
        
        # 创建IP到参与者ID的映射
        ip_to_participant = {}
        participant_lines = []
        for i, ip in enumerate(sorted(participants)[:6]):  # 限制最多6个参与者
            participant_id = f"P{i+1}"
            ip_to_participant[ip] = participant_id
            if ':' in ip:  # 包含端口
                participant_lines.append(f"participant {participant_id} as {ip}")
            else:
                participant_lines.append(f"participant {participant_id} as {ip}")
        
        # 按协议类型分组数据包
        dns_packets = []
        tcp_packets = []
        icmp_packets = []
        
        # 从flows中提取数据包信息
        for flow_key, flow_info in flows.items():
            if 'packets' in flow_info:
                for packet in flow_info['packets']:
                    if packet.get('protocol') == 'DNS':
                        dns_packets.append(packet)
                    elif packet.get('protocol') == 'TCP':
                        tcp_packets.append(packet)
                    elif packet.get('protocol') == 'ICMP':
                        icmp_packets.append(packet)
        
        # 生成DNS阶段
        dns_phase = []
        if dns_packets:
            dns_phase.append("Note over P1,P2: DNS阶段 (正常)")
            for i, packet in enumerate(dns_packets[:4]):  # 限制显示前4个DNS包
                src_ip = packet.get('src_ip', '')
                dst_ip = packet.get('dst_ip', '')
                src_participant = ip_to_participant.get(src_ip, 'P1')
                dst_participant = ip_to_participant.get(dst_ip, 'P2')
                packet_num = packet.get('packet_number', i+1)
                dns_phase.append(f"{src_participant}->>{dst_participant}: DNS查询 (UDP, packet{packet_num})")
                dns_phase.append(f"{dst_participant}-->>{src_participant}: DNS响应 (UDP, packet{packet_num+1})")
        
        # 生成TCP建链阶段
        tcp_connection_phase = []
        tcp_anomalies = [a for a in anomalies if a.get('type') == 'TCP_CONNECTION_INCOMPLETE']
        if tcp_anomalies:
            tcp_connection_phase.append("Note over P1,P3: 建链阶段 (异常)")
            for i, anomaly in enumerate(tcp_anomalies[:2]):  # 限制显示前2个异常
                flow = anomaly.get('flow', '')
                if flow:
                    # 从flow_key中提取IP地址
                    parts = flow.split('_')[1].split('-') if '_' in flow else flow.split('-')
                    if len(parts) >= 2:
                        src_ip = parts[0].split(':')[0]
                        dst_ip = parts[1].split(':')[0]
                        src_participant = ip_to_participant.get(src_ip, 'P1')
                        dst_participant = ip_to_participant.get(dst_ip, 'P3')
                        tcp_connection_phase.append(f"Note over {src_participant},{dst_participant}: 异常{i+1}: 持续重传, 未完成三次握手")
                        tcp_connection_phase.append(f"{src_participant}->>{dst_participant}: TCP请求 (packet{i*2+1})")
                        tcp_connection_phase.append(f"{src_participant}->>{dst_participant}: TCP重传 (packet{i*2+2}) // 异常:无响应")
        
        # 生成TCP传输阶段
        tcp_transmission_phase = []
        tcp_retransmissions = [a for a in anomalies if a.get('type') == 'TCP_RETRANSMISSION']
        if tcp_retransmissions:
            tcp_transmission_phase.append("Note over P1,P4: 传输阶段 (异常)")
            tcp_transmission_phase.append("Note over P3,P4: TCP传输异常")
            for i, anomaly in enumerate(tcp_retransmissions[:4]):  # 限制显示前4个重传
                flow = anomaly.get('flow', '')
                if flow:
                    # 从flow_key中提取IP地址
                    parts = flow.split('_')[1].split('-') if '_' in flow else flow.split('-')
                    if len(parts) >= 2:
                        src_ip = parts[0].split(':')[0]
                        dst_ip = parts[1].split(':')[0]
                        src_participant = ip_to_participant.get(src_ip, 'P1')
                        dst_participant = ip_to_participant.get(dst_ip, 'P3')
                        tcp_transmission_phase.append(f"{src_participant}->>{dst_participant}: TCP数据 (packet{i+1})")
                        tcp_transmission_phase.append("Note over P3,P4: 下行延迟")
        
        # 生成ICMP阶段
        icmp_phase = []
        if icmp_packets:
            icmp_phase.append("Note over P1,P3: ICMP传输 (异常)")
            for i, packet in enumerate(icmp_packets[:2]):  # 限制显示前2个ICMP包
                src_ip = packet.get('src_ip', '')
                dst_ip = packet.get('dst_ip', '')
                src_participant = ip_to_participant.get(src_ip, 'P1')
                dst_participant = ip_to_participant.get(dst_ip, 'P3')
                packet_num = packet.get('packet_number', i+1)
                icmp_phase.append(f"{src_participant}->>{dst_participant}: ICMP包 (packet{packet_num})")
                icmp_phase.append(f"{dst_participant}-->>{src_participant}: 目标主机强制禁止")
        
        # 组合所有阶段
        diagram_lines = ["sequenceDiagram"]
        diagram_lines.extend(participant_lines)
        diagram_lines.append("")
        
        if dns_phase:
            diagram_lines.extend(dns_phase)
            diagram_lines.append("")
        
        if tcp_connection_phase:
            diagram_lines.extend(tcp_connection_phase)
            diagram_lines.append("")
        
        if tcp_transmission_phase:
            diagram_lines.extend(tcp_transmission_phase)
            diagram_lines.append("")
        
        if icmp_phase:
            diagram_lines.extend(icmp_phase)
        
        return "\n".join(diagram_lines)

    def _generate_flows_content(self, flows):
        """生成网络流分析内容"""
        if not flows:
            return "<p>暂无网络流数据</p>"
        
        content = '<div class="flows-container">'
        
        # 按协议分组
        tcp_flows = {k: v for k, v in flows.items() if k.startswith('TCP_')}
        udp_flows = {k: v for k, v in flows.items() if k.startswith('UDP_')}
        other_flows = {k: v for k, v in flows.items() if not k.startswith(('TCP_', 'UDP_'))}
        
        # TCP流
        if tcp_flows:
            content += '<h3>TCP连接流</h3>'
            for flow_key, flow_info in list(tcp_flows.items())[:5]:  # 显示前5个
                content += self._format_flow_info(flow_key, flow_info)
        
        # UDP流
        if udp_flows:
            content += '<h3>UDP数据流</h3>'
            for flow_key, flow_info in list(udp_flows.items())[:5]:  # 显示前5个
                content += self._format_flow_info(flow_key, flow_info)
        
        content += '</div>'
        return content

    def _format_flow_info(self, flow_key, flow_info):
        """格式化流信息"""
        return f"""
        <div class="flow-item">
            <h4>{flow_key}</h4>
            <div class="flow-details">
                <p><strong>包数:</strong> {flow_info.get('packet_count', 0)}</p>
                <p><strong>持续时间:</strong> {flow_info.get('duration', 0):.2f}秒</p>
                <p><strong>总字节:</strong> {flow_info.get('total_bytes', 0)}</p>
                <p><strong>状态:</strong> {flow_info.get('tcp_analysis', {}).get('connection_status', 'N/A')}</p>
            </div>
        </div>
        """

    def _generate_anomalies_content(self, anomalies):
        """生成异常检测内容"""
        if not anomalies:
            return "<p>未检测到网络异常</p>"
        
        content = '<div class="anomalies-container">'
        
        for anomaly in anomalies:
            severity_color = {
                'HIGH': '#e74c3c',
                'MEDIUM': '#f39c12',
                'LOW': '#f1c40f'
            }.get(anomaly.get('severity', 'MEDIUM'), '#f39c12')
            
            content += f"""
            <div class="anomaly-item" style="border-left-color: {severity_color}">
                <h4>{anomaly.get('type', 'UNKNOWN')}</h4>
                <p><strong>严重程度:</strong> {anomaly.get('severity', 'UNKNOWN')}</p>
                <p><strong>描述:</strong> {anomaly.get('description', 'N/A')}</p>
                <p><strong>影响流:</strong> {anomaly.get('flow', 'N/A')}</p>
            </div>
            """
        
        content += '</div>'
        return content

    def _generate_statistics_content(self, statistics):
        """生成统计信息内容"""
        content = '<div class="statistics-container">'
        
        # 协议分布
        if 'protocols' in statistics:
            protocols = statistics['protocols']
            if 'protocol_distribution' in protocols:
                content += '<h3>协议分布</h3>'
                content += '<div class="protocol-chart">'
                for protocol, count in protocols['protocol_distribution'].items():
                    content += f'<div class="protocol-bar"><span>{protocol}</span><div class="bar" style="width: {min(count/10, 100)}%"></div><span>{count}</span></div>'
                content += '</div>'
        
        # 性能统计
        if 'performance' in statistics:
            perf = statistics['performance']
            content += '<h3>性能统计</h3>'
            content += f'<p><strong>总持续时间:</strong> {perf.get("total_duration", 0):.2f}秒</p>'
            content += f'<p><strong>平均包间隔:</strong> {perf.get("average_interval", 0):.4f}秒</p>'
            content += f'<p><strong>包率:</strong> {perf.get("packet_rate", 0):.2f} 包/秒</p>'
        
        content += '</div>'
        return content 

    def _generate_summary_content(self, summary, flows, anomalies):
        """生成总结内容"""
        # 计算准确的统计数据
        total_packets = summary.get('total_packets', 0)
        
        # 统计DNS查询数量
        dns_queries = 0
        for flow_key, flow_info in flows.items():
            if flow_info.get('protocol') == 'DNS':
                dns_queries += flow_info.get('packet_count', 0)
        
        # 统计TCP流数量
        tcp_flows = len([f for f in flows.values() if f.get('protocol') == 'TCP'])
        
        # 统计异常事件数量
        abnormal_events = len(anomalies)
        
        return f"""
        <div class="summary-content">
            <p><strong>总包数:</strong> {total_packets}</p>
            <p><strong>网络流数:</strong> {len(flows)}</p>
            <p><strong>异常事件:</strong> {abnormal_events}</p>
            <p><strong>分析状态:</strong> {'正常' if abnormal_events == 0 else '异常'}</p>
        </div>
        """

    def _generate_key_anomalies_content(self, anomalies):
        """生成关键异常点内容"""
        if not anomalies:
            return "<p>未发现关键异常点</p>"
        
        content = '<div class="key-anomalies-content">'
        
        # 按类型分组异常
        anomaly_types = {}
        for anomaly in anomalies:
            anomaly_type = anomaly.get('type', 'UNKNOWN')
            if anomaly_type not in anomaly_types:
                anomaly_types[anomaly_type] = []
            anomaly_types[anomaly_type].append(anomaly)
        
        # 计算总TCP流数量用于百分比计算
        # 由于这里没有flows参数，我们使用固定的14个TCP流作为基准
        total_tcp_flows = 14  # 根据实际数据分析
        
        # 生成分类的异常信息
        for anomaly_type, anomaly_list in anomaly_types.items():
            severity = anomaly_list[0].get('severity', 'MEDIUM')
            severity_text = {
                'HIGH': '高',
                'MEDIUM': '中',
                'LOW': '低'
            }.get(severity, '中')
            
            # 计算百分比
            if anomaly_type == 'TCP_CONNECTION_INCOMPLETE':
                percentage = len(anomaly_list) / total_tcp_flows * 100
                anomaly_name = 'TCP建链异常'
                anomaly_type_text = '连接失败'
                impact_text = f'{len(anomaly_list)}个服务器'
            elif anomaly_type == 'TCP_RETRANSMISSION':
                percentage = len(anomaly_list) / total_tcp_flows * 100
                anomaly_name = 'TCP传输异常'
                anomaly_type_text = '下行延迟'
                impact_text = f'{len(anomaly_list)}个传输流'
            elif 'ICMP' in anomaly_type:
                percentage = len(anomaly_list) / total_tcp_flows * 100
                anomaly_name = 'ICMP异常'
                anomaly_type_text = '被禁止'
                impact_text = f'{len(anomaly_list)}个ICMP流'
            else:
                percentage = len(anomaly_list) / total_tcp_flows * 100
                anomaly_name = anomaly_type.replace('_', ' ')
                anomaly_type_text = '未知类型'
                impact_text = f'{len(anomaly_list)}个异常'
            
            content += f"""
            <div class="key-anomaly-item">
                <h5>{anomaly_name} ({percentage:.0f}%)</h5>
                <p><strong>类型:</strong> {anomaly_type_text}</p>
                <p><strong>影响:</strong> {impact_text}</p>
                <div class="progress-bar">
                    <div class="progress-fill" style="width: {percentage}%"></div>
                </div>
            </div>
            """
        
        content += '</div>'
        return content

    def _generate_abnormal_process_content(self, anomalies):
        """生成异常流程内容"""
        content = '<div class="abnormal-process-content">'
        
        # 异常流程 - 去重处理
        tcp_incomplete_flows = set()
        for anomaly in anomalies:
            if anomaly.get('type') == 'TCP_CONNECTION_INCOMPLETE':
                flow = anomaly.get('flow', '')
                if flow:
                    tcp_incomplete_flows.add(flow)
        
        content += '<h5>1. 异常流程</h5>'
        if tcp_incomplete_flows:
            content += f'<p>• 发现 {len(tcp_incomplete_flows)} 个TCP连接未完成</p>'
            for flow in list(tcp_incomplete_flows)[:3]:  # 只显示前3个
                content += f'<p>  - {flow}</p>'
        else:
            content += '<p>• 未发现异常流程</p>'
        
        content += '</div>'
        return content

    def _generate_abnormal_message_content(self, anomalies):
        """生成异常消息内容"""
        content = '<div class="abnormal-message-content">'
        
        # 异常消息 - 去重处理
        retransmission_count = 0
        for anomaly in anomalies:
            if anomaly.get('type') == 'TCP_RETRANSMISSION':
                retransmission_count += 1
        
        content += '<h5>2. 异常消息</h5>'
        if retransmission_count > 0:
            content += f'<p>• 检测到 {retransmission_count} 个TCP重传事件</p>'
            content += '<p>• 网络传输存在丢包或延迟问题</p>'
        else:
            content += '<p>• 未发现异常消息</p>'
        
        content += '</div>'
        return content

    def _generate_abnormal_element_content(self, anomalies):
        """生成异常信元内容"""
        content = '<div class="abnormal-element-content">'
        
        content += '<h5>3. 异常信元</h5>'
        content += '<p>• 检查TCP标志位异常</p>'
        content += '<p>• 检查序列号异常</p>'
        content += '<p>• 检查窗口大小异常</p>'
        
        content += '</div>'
        return content

    def _generate_process_explanation_content(self):
        """生成异常流程解释内容"""
        return """
        <p>TCP连接建立需要三次握手：SYN、SYN-ACK、ACK。如果连接未完成，可能是网络问题、防火墙阻止或服务器不可达。</p>
        """

    def _generate_message_explanation_content(self):
        """生成异常消息解释内容"""
        return """
        <p>TCP重传表示数据包丢失或延迟，可能由网络拥塞、链路质量差或超时设置不当导致。</p>
        """

    def _generate_reason_code_explanation_content(self):
        """生成异常原因码解释内容"""
        return """
        <p>• RST：连接被重置，通常表示服务不可用或连接被拒绝</p>
        <p>• FIN：正常关闭连接</p>
        <p>• SYN：连接建立请求</p>
        <p>• ACK：确认响应</p>
        """

    def _generate_field_check_content(self, flows):
        """生成信元核查结果内容"""
        content = '<div class="field-check-content">'
        
        # 信元状态部分 - 2x2网格布局
        content += '''
        <div class="signal-element-grid">
            <div class="signal-element-panel">
                <div class="signal-element-item">
                    <span class="checkmark">✅</span>
                    <span class="element-text">TCP信元</span>
                    <span class="status-text">格式正确</span>
                </div>
            </div>
            <div class="signal-element-panel">
                <div class="signal-element-item">
                    <span class="checkmark">✅</span>
                    <span class="element-text">ICMP信元</span>
                    <span class="status-text">格式正确</span>
                </div>
            </div>
            <div class="signal-element-panel">
                <div class="signal-element-item">
                    <span class="checkmark">✅</span>
                    <span class="element-text">DNS信元</span>
                    <span class="status-text">格式正确</span>
                </div>
            </div>
            <div class="signal-element-panel">
                <div class="signal-element-item">
                    <span class="element-text">异常原因</span>
                    <span class="status-text">网络层面</span>
                </div>
            </div>
        </div>
        '''
        
        # 核查结论部分
        content += '''
        <div class="verification-conclusion">
            <h5>核查结论</h5>
            <p>所有协议信元格式均正确，异常主要出现在网络层面而非协议层面。TCP连接失败、ICMP被禁止、DNS查询正常都表明网络策略或连通性问题。</p>
        </div>
        '''
        
        content += '</div>'
        return content

    def _generate_problem_solution_content(self, anomalies, recommendations):
        """生成问题原因及处理措施内容"""
        content = '<div class="problem-solution-content">'
        
        # 问题原因 - 去重处理
        problem_types = set()
        for anomaly in anomalies:
            if anomaly.get('type') == 'TCP_CONNECTION_INCOMPLETE':
                problem_types.add('TCP连接未完成')
            elif anomaly.get('type') == 'TCP_RETRANSMISSION':
                problem_types.add('TCP重传')
            elif anomaly.get('type') == 'PORT_SCAN':
                problem_types.add('端口扫描')
        
        content += '<h5>问题原因</h5>'
        if problem_types:
            for problem in problem_types:
                content += f'<p>• {problem}</p>'
        else:
            content += '<p>• 未发现明显问题</p>'
        
        # 处理措施 - 去重处理
        unique_recommendations = {}
        for rec in recommendations:
            title = rec.get('title', '')
            if title not in unique_recommendations:
                unique_recommendations[title] = rec
        
        content += '<h5>处理措施</h5>'
        if unique_recommendations:
            for title, rec in unique_recommendations.items():
                content += f'''
                <div class="solution-item">
                    <p><strong>{title}</strong></p>
                    <p>{rec.get('description', 'N/A')}</p>
                    <ul>
                        {''.join(f'<li>{action}</li>' for action in rec.get('actions', []))}
                    </ul>
                </div>
                '''
        else:
            content += '<p>• 暂无具体处理措施</p>'
        
        content += '</div>'
        return content

    def _generate_recommendations_content(self, recommendations):
        """生成处理建议内容"""
        if not recommendations:
            return "<p>暂无处理建议</p>"
        
        content = '<div class="recommendations-container">'
        
        # 去重处理
        unique_recommendations = {}
        for rec in recommendations:
            title = rec.get('title', '')
            if title not in unique_recommendations:
                unique_recommendations[title] = rec
        
        for title, rec in unique_recommendations.items():
            priority_color = {
                'HIGH': '#e74c3c',
                'MEDIUM': '#f39c12',
                'LOW': '#27ae60'
            }.get(rec.get('priority', 'MEDIUM'), '#f39c12')
            
            content += f"""
            <div class="recommendation-item" style="border-left-color: {priority_color}">
                <h5>{title}</h5>
                <p><strong>优先级:</strong> {rec.get('priority', 'N/A')}</p>
                <p><strong>描述:</strong> {rec.get('description', 'N/A')}</p>
                <p><strong>建议操作:</strong></p>
                <ul>
                    {''.join(f'<li>{action}</li>' for action in rec.get('actions', []))}
                </ul>
            </div>
            """
        
        content += '</div>'
        return content 

    def _generate_short_term_suggestions(self, recommendations):
        """生成短期处理建议内容"""
        content = '<div class="short-term-suggestions">'
        content += '<h5>短期处理</h5>'
        content += '''
        <div class="solution-item">
            <p><strong>立即检查网络连通性</strong></p>
            <p>• 检查目标服务器状态和可达性</p>
            <p>• 验证防火墙规则配置</p>
            <p>• 检查网络路由和DNS解析</p>
        </div>
        <div class="solution-item">
            <p><strong>优化TCP连接参数</strong></p>
            <p>• 调整TCP超时设置</p>
            <p>• 优化重传机制</p>
            <p>• 检查网络拥塞情况</p>
        </div>
        '''
        content += '</div>'
        return content

    def _generate_long_term_suggestions(self, recommendations):
        """生成长期优化建议内容"""
        content = '<div class="long-term-suggestions">'
        content += '<h5>长期优化</h5>'
        content += '''
        <div class="solution-item">
            <p><strong>网络架构优化</strong></p>
            <p>• 升级网络设备性能</p>
            <p>• 优化网络拓扑结构</p>
            <p>• 实施负载均衡策略</p>
        </div>
        <div class="solution-item">
            <p><strong>监控体系建设</strong></p>
            <p>• 建立实时网络监控</p>
            <p>• 设置告警阈值</p>
            <p>• 完善日志分析系统</p>
        </div>
        '''
        content += '</div>'
        return content

    def _generate_technical_suggestions(self, recommendations):
        """生成技术建议内容"""
        content = '<div class="technical-suggestions">'
        content += '<h5>技术建议</h5>'
        content += '''
        <div class="solution-item">
            <p><strong>协议优化建议</strong></p>
            <p>• 使用TCP窗口缩放</p>
            <p>• 启用选择性确认(SACK)</p>
            <p>• 优化MTU设置</p>
        </div>
        <div class="solution-item">
            <p><strong>安全策略建议</strong></p>
            <p>• 审查ICMP策略</p>
            <p>• 优化防火墙规则</p>
            <p>• 加强网络安全防护</p>
        </div>
        '''
        content += '</div>'
        return content

    def _generate_tcp_connection_failure_reasons(self, anomalies):
        """生成TCP建链失败原因内容"""
        content = '<div class="tcp-connection-failure-reasons">'
        content += '<h5>TCP建链失败原因</h5>'
        tcp_connection_anomalies = [a for a in anomalies if a.get('type') == 'TCP_CONNECTION_INCOMPLETE']
        if tcp_connection_anomalies:
            content += '''
            <div class="solution-item">
                <p><strong>网络层面问题</strong></p>
                <p>• 目标服务器不可达或服务未启动</p>
                <p>• 防火墙阻止连接建立</p>
                <p>• 网络路由配置错误</p>
                <p>• 网络拥塞导致超时</p>
            </div>
            <div class="solution-item">
                <p><strong>协议层面问题</strong></p>
                <p>• TCP三次握手未完成</p>
                <p>• 序列号异常或窗口大小问题</p>
                <p>• 连接超时设置过短</p>
                <p>• 端口被占用或服务异常</p>
            </div>
            '''
        else:
            content += '<p>• 未发现TCP建链失败</p>'
        content += '</div>'
        return content

    def _generate_tcp_transmission_delay_reasons(self, anomalies):
        """生成TCP传输延迟原因内容"""
        content = '<div class="tcp-transmission-delay-reasons">'
        content += '<h5>TCP传输延迟原因</h5>'
        tcp_retransmissions = [a for a in anomalies if a.get('type') == 'TCP_RETRANSMISSION']
        if tcp_retransmissions:
            content += '''
            <div class="solution-item">
                <p><strong>网络传输问题</strong></p>
                <p>• 网络拥塞导致数据包丢失</p>
                <p>• 链路质量差，误码率高</p>
                <p>• 网络设备处理能力不足</p>
                <p>• 带宽利用率过高</p>
            </div>
            <div class="solution-item">
                <p><strong>配置参数问题</strong></p>
                <p>• TCP超时设置不当</p>
                <p>• 重传机制配置错误</p>
                <p>• 窗口大小设置不合理</p>
                <p>• 拥塞控制算法不当</p>
            </div>
            '''
        else:
            content += '<p>• 未发现TCP传输延迟</p>'
        content += '</div>'
        return content

    def _generate_icmp_forbidden_reasons(self, anomalies):
        """生成ICMP被禁止原因内容"""
        content = '<div class="icmp-forbidden-reasons">'
        content += '<h5>ICMP被禁止原因</h5>'
        icmp_anomalies = [a for a in anomalies if 'ICMP' in a.get('type', '')]
        if icmp_anomalies:
            content += '''
            <div class="solution-item">
                <p><strong>安全策略限制</strong></p>
                <p>• 防火墙策略阻止ICMP流量</p>
                <p>• 网络安全策略配置</p>
                <p>• 入侵检测系统拦截</p>
                <p>• 网络访问控制列表(ACL)限制</p>
            </div>
            <div class="solution-item">
                <p><strong>网络配置问题</strong></p>
                <p>• 路由器ICMP配置错误</p>
                <p>• 目标主机ICMP服务关闭</p>
                <p>• 网络设备ICMP策略设置</p>
                <p>• 运营商网络限制</p>
            </div>
            '''
        else:
            content += '''
            <div class="solution-item">
                <p><strong>ICMP策略说明</strong></p>
                <p>• ICMP协议被网络策略禁止</p>
                <p>• 可能影响网络诊断和故障排查</p>
                <p>• 建议根据业务需求调整ICMP策略</p>
            </div>
            '''
        content += '</div>'
        return content

    def _generate_concise_recommendation_paragraph(self, recommendations, anomalies, flows, statistics, complaint):
        """生成面向核心网运维的一段式具体处理建议（中文）。
        该段落会结合异常类型、受影响流和性能指标，输出可直接用于处置/投诉判断的文字。"""
        # 统计异常
        incomplete_list = [a for a in anomalies if a.get('type') == 'TCP_CONNECTION_INCOMPLETE']
        retx_list = [a for a in anomalies if a.get('type') == 'TCP_RETRANSMISSION']
        incomplete_cnt = len(incomplete_list)
        retx_cnt = len(retx_list)

        # 提取主要受影响的目的端点（IP:Port）
        dest_endpoints = []
        for a in anomalies:
            flow_key = a.get('flow') or ''
            if '_' in flow_key and '-' in flow_key:
                try:
                    parts = flow_key.split('_', 1)[1].split('-')
                    if len(parts) >= 2:
                        dest = parts[1]
                        dest_endpoints.append(dest)
                except Exception:
                    pass
        # 去重并保留前若干个用于展示
        unique_dests = []
        seen = set()
        for d in dest_endpoints:
            if d not in seen:
                seen.add(d)
                unique_dests.append(d)
        impact_sample = '、'.join(unique_dests[:3]) if unique_dests else '若干目标服务器/端口'

        # 性能指标
        packet_rate = statistics.get('performance', {}).get('packet_rate', 0)
        total_packets = statistics.get('protocols', {}).get('protocol_distribution', {})

        # 从recommendations中提炼首要处置方向关键词（可选）
        priority_map = {'HIGH': 3, 'MEDIUM': 2, 'LOW': 1}
        recommendations_sorted = sorted(recommendations or [], key=lambda r: priority_map.get(r.get('priority', 'MEDIUM'), 2), reverse=True)
        first_title = recommendations_sorted[0]['title'] if recommendations_sorted else '连接与传输质量核查'

        # 投诉上下文信息
        complaint_summary = (complaint or {}).get('summary')
        whitelist_ips = (complaint or {}).get('whitelist_ips') or []
        whitelist_cidr = (complaint or {}).get('whitelist_cidr')
        msisdn = (complaint or {}).get('msisdn')
        imsi = (complaint or {}).get('imsi')
        apn = (complaint or {}).get('apn')
        location = (complaint or {}).get('location')
        report_time = (complaint or {}).get('report_time')

        # 将投诉关键信息拼接为一句上下文
        complaint_clause_parts = []
        if complaint_summary:
            complaint_clause_parts.append(complaint_summary.strip())
        if whitelist_ips:
            complaint_clause_parts.append(f"涉及IP {','.join(whitelist_ips)}")
        if whitelist_cidr:
            complaint_clause_parts.append(f"白名单 {whitelist_cidr}")
        if apn:
            complaint_clause_parts.append(f"APN {apn}")
        if msisdn:
            complaint_clause_parts.append(f"号码 {msisdn}")
        if report_time:
            complaint_clause_parts.append(f"投诉时间 {report_time}")
        if location:
            complaint_clause_parts.append(f"归属地 {location}")
        complaint_clause = '；'.join(complaint_clause_parts)

        # 将关键处置建议加粗标红
        key_actions = (
            "为快速支撑投诉与处置，建议先在核心网/承载网侧对上述端点进行连通性核查（服务存活、端口放通、路由与NAT会话），"
            "重点比对抓包时段的防火墙/ACL命中与丢弃日志；若链路无异常但仍存在重传，建议临时放宽 SYN/RST 相关策略并回归测试，"
            "同时对拥塞与丢包进行观测，必要时调高会话超时与初始重传间隔，或评估链路带宽与队列策略优化。"
        )
        key_actions_html = f"<span style=\"color:#e74c3c; font-weight:bold\">{''.join(key_actions)}</span>"

        # 生成一段话（避免条目化）
        paragraph = (
            (f"【投诉信息】{complaint_clause}。" if complaint_clause else "") +
            f"本次抓包显示 TCP 建链未完成 {incomplete_cnt} 起、TCP 重传 {retx_cnt} 起，主要涉及 {impact_sample} 等目的端点；"
            + key_actions_html +
            f"上述处置完成后，安排一次同条件复现拨测并回收日志，结合{first_title}结果输出最终结论，用于与用户沟通和投诉判责。"
        )

        return f"<div class=\"recommendation-item\"><p>{paragraph}</p></div>"

    def _get_css_styles(self):
        """获取CSS样式"""
        return """* {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Microsoft YaHei', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            color: #333;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            overflow-x: hidden;
        }

        .main-container {
            display: flex;
            min-height: 100vh;
        }

        .main-content {
            flex: 1;
            padding: 20px;
            transition: margin-right 0.3s ease;
        }

        .main-content.expanded {
            margin-right: 500px;
        }

        .header {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 15px;
            padding: 30px;
            margin-bottom: 30px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
            text-align: center;
        }

        .header h1 {
            color: #2c3e50;
            font-size: 2.5em;
            margin-bottom: 10px;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
        }

        .header .subtitle {
            color: #7f8c8d;
            font-size: 1.2em;
            margin-bottom: 20px;
        }

        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            gap: 15px;
            margin-bottom: 20px;
        }

        .stat-card {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 10px;
            padding: 15px;
            text-align: center;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
            transition: transform 0.3s ease;
        }

        .stat-card:hover {
            transform: translateY(-3px);
        }

        .stat-number {
            font-size: 2em;
            font-weight: bold;
            color: #3498db;
            margin-bottom: 5px;
        }

        .stat-label {
            color: #7f8c8d;
            font-size: 0.9em;
        }

        .analysis-section {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 15px;
            padding: 30px;
            margin-bottom: 30px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
        }

        .analysis-section h2 {
            color: #2c3e50;
            font-size: 1.8em;
            margin-bottom: 20px;
            border-bottom: 3px solid #3498db;
            padding-bottom: 10px;
        }

        .flows-container, .anomalies-container, .statistics-container, .signaling-flow-container {
            margin-top: 20px;
        }

        .flow-item, .anomaly-item {
            background: #f8f9fa;
            border-radius: 8px;
            padding: 15px;
            margin: 10px 0;
            border-left: 4px solid #3498db;
        }

        .flow-item h4, .anomaly-item h4 {
            color: #2c3e50;
            margin-bottom: 10px;
        }

        .flow-details p {
            margin: 5px 0;
            color: #7f8c8d;
        }

        .protocol-chart {
            margin: 20px 0;
        }

        .protocol-bar {
            display: flex;
            align-items: center;
            margin: 10px 0;
            gap: 10px;
        }

        .protocol-bar .bar {
            height: 20px;
            background: linear-gradient(90deg, #3498db, #2980b9);
            border-radius: 10px;
            min-width: 50px;
        }

        .mermaid-diagram {
            background: #f8f9fa;
            border-radius: 8px;
            padding: 20px;
            margin: 20px 0;
        }

        .signaling-flow-diagram {
            background: #2c3e50;
            border-radius: 15px;
            padding: 30px;
            margin: 20px 0;
            color: white;
        }

        .flow-chart {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 10px;
        }

        .flow-chart .flow-item {
            text-align: center;
            width: 100%;
            max-width: 600px;
            background: transparent;
            border-left: none;
            padding: 0;
            margin: 0;
        }

        .flow-header {
            background: rgba(255, 255, 255, 0.1);
            border-radius: 8px;
            padding: 15px;
            font-weight: bold;
            font-size: 1.1em;
            color: white;
        }

        .flow-arrow {
            font-size: 1.5em;
            color: #3498db;
            margin: 10px 0;
        }

        .flow-details {
            background: rgba(255, 255, 255, 0.05);
            border-radius: 8px;
            padding: 15px;
            margin: 10px 0;
        }

        .flow-branch {
            text-align: left;
            margin: 5px 0;
            padding: 5px 0;
            color: white;
        }

        .flow-branch.anomaly {
            color: #e74c3c;
            font-weight: bold;
        }

        .anomaly-summary {
            background: rgba(231, 76, 60, 0.1);
            border-radius: 8px;
            padding: 20px;
            margin-top: 20px;
        }

        .anomaly-summary h4 {
            color: #e74c3c;
            margin-bottom: 15px;
        }

        .anomaly-summary .anomaly-item {
            margin: 8px 0;
            padding: 5px 0;
            color: white;
            background: transparent;
            border-left: none;
        }

        .signal-element-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
            margin-bottom: 20px;
        }

        .signal-element-panel {
            background: #f8f9fa;
            border-radius: 8px;
            padding: 15px;
            border-left: 4px solid #3498db;
        }

        .signal-element-item {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .checkmark {
            font-size: 1.2em;
            color: #27ae60;
        }

        .element-text {
            font-weight: bold;
            color: #2c3e50;
        }

        .status-text {
            color: #27ae60;
            font-weight: bold;
        }

        .verification-conclusion {
            background: #e3f2fd;
            border-radius: 8px;
            padding: 20px;
            margin-top: 15px;
        }

        .verification-conclusion h5 {
            color: #1976d2;
            margin-bottom: 10px;
        }

        .verification-conclusion p {
            color: #2c3e50;
            line-height: 1.6;
        }

        .flow-phases {
            margin-top: 30px;
        }

        .phase-analysis {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-top: 15px;
        }

        .phase-item {
            background: #f8f9fa;
            border-radius: 8px;
            padding: 15px;
            border-left: 4px solid #3498db;
        }

        .sidebar {
            position: fixed;
            right: 0;
            top: 0;
            width: 500px;
            height: 100vh;
            background: rgba(255, 255, 255, 0.98);
            box-shadow: -5px 0 20px rgba(0, 0, 0, 0.1);
            overflow-y: auto;
            transition: transform 0.3s ease;
            z-index: 1000;
        }

        .sidebar.collapsed {
            transform: translateX(100%);
        }

        .sidebar-toggle {
            position: fixed;
            right: 20px;
            top: 20px;
            background: #3498db;
            color: white;
            border: none;
            padding: 10px 15px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 1em;
            z-index: 1001;
            transition: background 0.3s ease;
        }

        .sidebar-toggle:hover {
            background: #2980b9;
        }

        .sidebar-header {
            background: #2c3e50;
            color: white;
            padding: 20px;
            text-align: center;
            position: sticky;
            top: 0;
            z-index: 10;
        }

        .sidebar-content {
            padding: 20px;
        }

        .sidebar-section {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 20px;
            margin-bottom: 20px;
            border-left: 4px solid #3498db;
        }

        .sidebar-section h4 {
            color: #2c3e50;
            font-size: 1.2em;
            margin-bottom: 15px;
            border-bottom: 2px solid #3498db;
            padding-bottom: 8px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: space-between;
            word-wrap: break-word;
            word-break: break-all;
        }

        .section-toggle {
            background: none;
            border: none;
            color: #3498db;
            font-size: 1.2em;
            cursor: pointer;
            padding: 0;
            width: 24px;
            height: 24px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            transition: all 0.3s ease;
            flex-shrink: 0;
        }

        .section-content {
            max-height: 0;
            overflow: hidden;
            transition: max-height 0.3s ease;
            word-wrap: break-word;
            word-break: break-all;
            line-height: 1.4;
        }

        .section-content.expanded {
            max-height: 2000px;
        }

        .sub-section {
            background: #e0e0e0;
            border-radius: 6px;
            padding: 10px 15px;
            margin-bottom: 10px;
            border-left: 3px solid #3498db;
        }

        .sub-item {
            color: #2c3e50;
            font-size: 1em;
            margin-bottom: 5px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 5px 0;
        }

        .sub-item .sub-toggle {
            font-size: 0.8em;
            color: #7f8c8d;
            transition: transform 0.3s ease;
        }

        .sub-item:hover .sub-toggle {
            transform: rotate(90deg);
        }

        .sub-content {
            max-height: 0;
            overflow: hidden;
            transition: max-height 0.3s ease;
            padding-left: 20px;
            word-wrap: break-word;
            word-break: break-all;
            line-height: 1.4;
        }

        .sub-content.expanded {
            max-height: 2000px;
        }

        .recommendation-item, .key-anomaly-item, .field-check-item, .solution-item {
            background: #ffffff;
            border-radius: 8px;
            padding: 15px;
            margin: 10px 0;
            border-left: 4px solid #f39c12;
        }

        .recommendation-item h5, .key-anomaly-item h5 {
            color: #2c3e50;
            margin-bottom: 10px;
        }

        .export-btn {
            background: #3498db;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 0.9em;
            margin: 5px;
            transition: background 0.3s ease;
        }

        .export-btn:hover {
            background: #2980b9;
        }

        .footer {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 15px;
            padding: 20px;
            text-align: center;
            color: #7f8c8d;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
        }

        .key-anomaly-item {
            background: #fff3cd;
            border-radius: 8px;
            padding: 15px;
            margin: 10px 0;
            border-left: 4px solid #f39c12;
        }

        .key-anomaly-item h5 {
            color: #2c3e50;
            margin-bottom: 10px;
        }

        .progress-bar {
            width: 100%;
            height: 8px;
            background-color: #e9ecef;
            border-radius: 4px;
            margin-top: 10px;
            overflow: hidden;
        }

        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #f39c12, #e67e22);
            border-radius: 4px;
            transition: width 0.3s ease;
        }

        @media (max-width: 1200px) {
            .main-content.expanded {
                margin-right: 0;
            }
            
            .sidebar {
                width: 100%;
                max-width: 500px;
            }
        }"""

    def _get_javascript_code(self):
        """获取JavaScript代码"""
        return """// 初始化Mermaid
        mermaid.initialize({ startOnLoad: true });

        // Sidebar切换功能
        function toggleSidebar() {
            const sidebar = document.getElementById('sidebar');
            const mainContent = document.getElementById('mainContent');
            const toggleBtn = document.getElementById('sidebarToggle');
            
            if (sidebar.classList.contains('collapsed')) {
                sidebar.classList.remove('collapsed');
                mainContent.classList.add('expanded');
                toggleBtn.textContent = '收起报告';
            } else {
                sidebar.classList.add('collapsed');
                mainContent.classList.remove('expanded');
                toggleBtn.textContent = '展开报告';
            }
        }

        // Section切换功能
        function toggleSection(sectionElement) {
            const sectionContent = sectionElement.nextElementSibling;
            if (sectionContent && sectionContent.classList.contains('section-content')) {
                sectionContent.classList.toggle('expanded');
                const toggleBtn = sectionElement.querySelector('.section-toggle');
                if (toggleBtn) {
                    toggleBtn.textContent = sectionContent.classList.contains('expanded') ? '▼' : '▶';
                }
            }
        }

        // Sub-section切换功能
        function toggleSubSection(subItemElement) {
            const subContent = subItemElement.nextElementSibling;
            if (subContent && subContent.classList.contains('sub-content')) {
                subContent.classList.toggle('expanded');
                const subToggle = subItemElement.querySelector('.sub-toggle');
                if (subToggle) {
                    subToggle.textContent = subContent.classList.contains('expanded') ? '▼' : '▶';
                }
            }
        }

        // 打印报告
        function printReport() {
            window.print();
        }

        // 保存为HTML文件
        function saveAsHTML() {
            const htmlContent = document.documentElement.outerHTML;
            const blob = new Blob([htmlContent], { type: 'text/html' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = '用户面信令分析报告.html';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 默认关闭sidebar
            setTimeout(() => {
                // 不自动展开sidebar，保持关闭状态
            }, 1000);
        });"""

    def _load_complaint_context(self, docs_dir):
        """从docs目录加载投诉上下文，可选文件：complaint_context.json"""
        try:
            path = Path(docs_dir) / "complaint_context.json"
            if path.exists():
                with open(path, 'r', encoding='utf-8') as f:
                    return json.load(f)
        except Exception:
            pass
        return {}

def main():
    """主函数"""
    parser = argparse.ArgumentParser(description="Web Page Generator Tool")
    parser.add_argument("docs_dir", help="Analysis results documents directory")
    parser.add_argument("styles_dir", help="Styles files directory")
    parser.add_argument("project_root", help="Project root directory")
    
    args = parser.parse_args()
    
    # 创建网页生成器实例
    generator = WebGenerator()
    
    # 生成网页
    success = generator.generate_web_page(args.docs_dir, args.styles_dir, args.project_root)
    
    if success:
        print("Web page generation completed!")
        sys.exit(0)
    else:
        print("Web page generation failed!")
        sys.exit(1)

if __name__ == "__main__":
    main() 